import pandas as pd
import numpy as np
# from sklearn import tree
from sklearn.ensemble import RandomForestRegressor
from sklearn.externals import joblib
from sklearn.metrics import mean_squared_error as mse

data_train = pd.read_csv('data_train.txt', index_col=[0], header=0)
data_valid = pd.read_csv('data_train.txt', index_col=[0], header=0)
# 完整的
data_train = data_train.append(data_valid)

features_list = list(data_train.columns)[3:7] + list(data_train.columns)[8:]
train_subset = data_train.loc[:, features_list]
valid_subset = data_valid.loc[:, features_list]
train_subset.head()


def random_forest(data_train, data_test, estimator, depth, leaf_num, split_num, init=False):
    if init:
        data_test['repost_hat'] = 0
        data_test['comments_hat'] = 0
        data_test['likes_hat'] = 0
    else:
        pass

    # 噪音数据预测值均为0,因此仅处理非噪音数据
    train = data_train[data_train['logit'] == 0]
    test = data_test[data_test['logit'] == 0]

    # 分别对转发，评论和点赞建立三个森林
    forest_repost = RandomForestRegressor(n_estimators=estimator, oob_score=True, n_jobs=-1, random_state=50,
                                          max_features="auto", max_depth=depth, min_samples_leaf=leaf_num,
                                          min_samples_split=split_num)  # criterion defalut by 'mse'
    forest_comments = RandomForestRegressor(n_estimators=estimator, oob_score=True, n_jobs=-1, random_state=50,
                                            max_features="auto", max_depth=depth, min_samples_leaf=leaf_num,
                                            min_samples_split=split_num)
    forest_likes = RandomForestRegressor(n_estimators=estimator, oob_score=True, n_jobs=-1, random_state=50,
                                         max_features="auto", max_depth=depth, min_samples_leaf=leaf_num,
                                         min_samples_split=split_num)
    # forest_repost = RandomForestRegressor(n_estimators = estimator, oob_score = True, n_jobs = -1
    #                            max_features = "auto") # criterion defalut by 'mse'
    # forest_comments= RandomForestRegressor(n_estimators = estimator, oob_score = True, n_jobs = -1,random_state =42,
    #                            max_features = "auto")
    # forest_likes = RandomForestRegressor(n_estimators = estimator, oob_score = True, n_jobs = -1,random_state =42,
    #                            max_features = "auto")

    # 拟合三个森林
    regressor_train = train.drop(['repost', 'comments', 'likes', 'logit'], axis=1, inplace=False)
    repost_train = train.loc[:, ['repost']]
    comments_train = train.loc[:, ['comments']]
    likes_train = train.loc[:, ['likes']]
    predict_repost = forest_repost.fit(regressor_train, repost_train.values.ravel())  # shape warning remove
    predict_comments = forest_comments.fit(regressor_train, comments_train.values.ravel())
    predict_likes = forest_likes.fit(regressor_train, likes_train.values.ravel())
    print(predict_repost.oob_score_, predict_comments.oob_score_, predict_likes.oob_score_)

    # 预测测试集的数据
    regressor_test = test.drop(['repost', 'comments', 'likes', 'logit', 'repost_hat', 'comments_hat', 'likes_hat'],
                               axis=1, inplace=False)
    repost_hat = np.round(predict_repost.predict(regressor_test), 0)  # round函数只是返回四舍五入值，是浮点类型
    comments_hat = np.round(predict_comments.predict(regressor_test), 0)
    likes_hat = np.round(predict_likes.predict(regressor_test), 0)

    # 将预测值赋值并设置为整数值
    data_test['repost_hat'][data_test['logit'] == 0] = repost_hat
    data_test['comments_hat'][data_test['logit'] == 0] = comments_hat
    data_test['likes_hat'][data_test['logit'] == 0] = likes_hat
    data_test['repost_hat'] = data_test['repost_hat'].apply(lambda x: int(x))
    data_test['comments_hat'] = data_test['comments_hat'].apply(lambda x: int(x))
    data_test['likes_hat'] = data_test['likes_hat'].apply(lambda x: int(x))
    return data_test


estimators = 1000
oob = True
random_num = 42
jobs = -1
depth = 50
leaf_num = 10
split_num = 50


def precision(data):
    data['deviation_repost'] = list(map(lambda x, y: abs(x - y) / (y + 5), data['repost_hat'], data['repost']))
    # print (data['deviation_repost'])
    data['deviation_likes'] = list(map(lambda x, y: abs(x - y) / (y + 3), data['likes_hat'], data['likes']))
    # print (data['deviation_likes'])
    data['deviation_comments'] = list(map(lambda x, y: abs(x - y) / (y + 3), data['comments_hat'], data['comments']))
    # print (data['deviation_comments'])
    data['lcf_sum'] = data['repost'] + data['likes'] + data['comments']
    # print (data['lcf_sum'])
    data['lcf_sum'] = data['lcf_sum'].apply(lambda x: 100 if x > 100 else x)
    data['precision_1_-0.8'] = 1 - 0.5 * data['deviation_repost'] - 0.25 * data['deviation_likes'] - 0.25 * data[
        'deviation_comments'] - 0.8
    # print (data['precision_1_-0.8'])
    data.loc[data['precision_1_-0.8'] <= 0, 'sgn'] = 0
    data.loc[data['precision_1_-0.8'] > 0, 'sgn'] = 1
    # print (data['sgn'])
    precision_ = sum((data['lcf_sum'] + 1) * data['sgn']) / sum(data['lcf_sum'] + 1)
    return precision_


x = data_train[features_list]
y = data_train['repost']
model_repost = RandomForestRegressor(n_estimators=estimators, oob_score=oob, random_state=random_num, n_jobs=jobs,
                                     max_features="auto", max_depth=depth, min_samples_leaf=leaf_num,
                                     min_samples_split=split_num)
model_repost.fit(x, y)
# model_repost.score

x = data_train[features_list]
y = data_train['comments']
model_comments = RandomForestRegressor(n_estimators=estimators, oob_score=oob, random_state=random_num, n_jobs=jobs,
                                       max_features="auto", max_depth=depth, min_samples_leaf=leaf_num,
                                       min_samples_split=split_num)
model_comments.fit(x, y)
# model_comments.score

x = data_train[features_list]
y = data_train['likes']
model_likes = RandomForestRegressor(n_estimators=estimators, oob_score=oob, random_state=random_num, n_jobs=jobs,
                                    max_features="auto", max_depth=depth, min_samples_leaf=leaf_num,
                                    min_samples_split=split_num)
model_likes.fit(x, y)

model_repost.oob_score_, model_comments.oob_score_, model_likes.oob_score_
